<!-- eslint-disable vue/multi-word-component-names -->
<script>
import { watchEffect } from 'vue';

// 生成幂集的算法
function bwPowerSet(originalSet) {
  const subSets = [];
  const numberOfCombinations = 2 ** originalSet.length;

  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
    const subSet = [];

    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
      if (combinationIndex & (1 << setElementIndex)) {
        subSet.push(originalSet[setElementIndex]);
      }
    }

    subSets.push(subSet);
  }

  return subSets;
}

// 生成有效路径字典对象
function getPathMap(skus) {
  const _pathMap = {};

  // 根据 skus 字段生成有效的 sku 数组
  const effectiveSkus = skus.filter(sku => sku.inventory > 0);

  // 根据有效的 sku 使用算法
  effectiveSkus.forEach(sku => {
    const selectedOptionArr = sku.specs.map(option => option.valueName);
    const optionArrPowerSet = bwPowerSet(selectedOptionArr);
    optionArrPowerSet.forEach(arr => {
      const key = arr.join('-');
      if (_pathMap[key]) {
        _pathMap[key].push(sku.id);
      } else {
        _pathMap[key] = [sku.id];
      }
    });
  });

  return _pathMap;
};

// 初始化禁用状态
function initDisabledStatus(specs, pathMap) {
  specs.forEach(spec => {
    spec.values.forEach(option => {
      if (pathMap[option.name]) {
        option.disabled = false;
      } else {
        option.disabled = true;
      }
    });
  });
};

// 获取选中项的匹配数组
function getSelectedOptions(specs) {
  const arr = [];
  specs.forEach(spec => {
    const selectedOption = spec.values.find(option => option.selected);
    arr.push(selectedOption ? selectedOption.name : undefined);
  });
  return arr;
};

// 切换时更新禁用状态
function updateDisabledStatus(specs, pathMap) {
  const selectedOptions = getSelectedOptions(specs);
  specs.forEach((spec, index) => {
    spec.values.forEach(option => {
      selectedOptions[index] = option.name;
      const key = selectedOptions.filter(option => option).join('-');
      option.disabled = !pathMap[key];
    });
  });
};

export default {
  name: 'Sku',
  props: {
    goods: {
      type: Object,
      default: () => ({ specs: [], skus: [] })
    }
  },
  emits: ['change'],
  setup(props, { emit }) {
    let pathMap = {};

    watchEffect(() => {
      pathMap = getPathMap(props.goods.skus);
      initDisabledStatus(props.goods.specs, pathMap);
    });

    // 切换选中状态
    const changeSelectedStatus = (spec, option) => {
      if (option.disabled) {
        return false;
      }

      if (option.selected) {
        option.selected = false;
      } else {
        spec.values.forEach(op => op.selected = false);
        option.selected = true;
      }

      const specs = props.goods.specs;
      updateDisabledStatus(specs, pathMap);

      const selectedOptions = getSelectedOptions(specs).filter(option => option);
      if (selectedOptions.length === specs.length) {
        const key = selectedOptions.join('-');
        const skuId = pathMap[key][0];

        const skuObj = props.goods.skus.find(item => item.id === skuId);
        emit('change', {
          skuId: skuObj.id,
          price: skuObj.price,
          oldPrice: skuObj.oldPrice,
          inventory: skuObj.inventory,
          specsText: skuObj.specs.reduce((p, n) => `${p} ${n.name}：${n.valueName}`, '').trim()
        });
      } else {
        emit('change', {});
      }
    };
    return { changeSelectedStatus };
  }
};
</script>

<template>
  <div class="goods-sku">
    <dl v-for="spec in goods.specs" :key="spec.id">
      <dt>{{ spec.name }}</dt>
      <dd>
        <template v-for="option in spec.values" :key="option.name">
          <!-- 图片类型规格 -->
          <img v-if="option.picture" :src="option.picture" :title="option.name"
            @click="changeSelectedStatus(spec, option)"
            :class="{ selected: option.selected, disabled: option.disabled }">
          <!-- 文字类型规格 -->
          <span v-else @click="changeSelectedStatus(spec, option)"
            :class="{ selected: option.selected, disabled: option.disabled }">
            {{ option.name }}
          </span>
        </template>
      </dd>
    </dl>
  </div>
</template>

<style scoped lang="scss">
@mixin sku-state-mixin {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
    border-color: #27ba9b;
  }

  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      >img {
        width: 50px;
        height: 50px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }

      >span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }
    }
  }
}
</style>